<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" lang="cn">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>alatka-rule-admin</title>
    <link rel="stylesheet" th:href="@{/webjars/bootstrap/css/bootstrap.min.css}"/>
    <link rel="stylesheet" th:href="@{/webjars/bootstrap-icons/font/bootstrap-icons.min.css}"/>
    <link rel="stylesheet" th:href="@{/webjars/tom-select/dist/css/tom-select.bootstrap5.min.css}"/>
    <link rel="stylesheet" th:href="@{/webjars/bootstrap-table/dist/bootstrap-table.min.css}"/>
    <style>
        .list-group-item.light-active {
            background-color: hsl(210, 100%, 90%);
        }

        .clickable-badge {
            cursor: pointer;
            transition: all 0.2s ease-in-out;
        }
    </style>
</head>
<body>
<div class="container mt-4">
    <div class="card mb-3">
        <div class="card-header bg-light d-flex justify-content-between align-items-center">
            <h5 class="mb-0">规则查询</h5>
            <button class="btn btn-sm btn-outline-secondary"
                    type="button"
                    data-bs-toggle="collapse"
                    data-bs-target="#cardCollapse"
                    aria-expanded="true"
                    aria-controls="cardCollapse">
                <i class="bi bi-arrows-angle-contract"></i>
            </button>
        </div>
        <div class="card-body collapse show" id="cardCollapse">
            <form id="searchForm" class="row g-3">
                <div class="col-md-3">
                    <label for="name" class="form-label">名称</label>
                    <input type="text" class="form-control" id="name" name="name" placeholder="输入名称">
                </div>
                <div class="col-md-6">
                    <label for="desc" class="form-label">描述</label>
                    <input type="text" class="form-control" id="desc" name="desc" placeholder="输入名称">
                </div>
                <div class="col-md-3">
                    <label for="type" class="form-label">类型</label>
                    <select class="form-select alk-select-type" id="type" name="type">
                        <option value="">全部</option>
                    </select>
                </div>
                <div class="col-md-3">
                    <label for="groupKey" class="form-label">规则组名称</label>
                    <select class="form-select alk-select-groupKey" id="groupKey" name="groupKey">
                        <option value="default_">默认组</option>
                    </select>
                </div>
                <div class="col-md-3">
                    <label for="enabled" class="form-label">是否可用</label>
                    <select class="form-select" id="enabled" name="enabled">
                        <option value="">全部</option>
                        <option value="true" selected>正常</option>
                        <option value="false">禁用</option>
                    </select>
                </div>
                <div class="col-12 text-center">
                    <button type="button" class="btn btn-secondary me-2" id="resetButton">
                        <i class="bi bi-arrow-counterclockwise"></i> 重置
                    </button>
                    <button type="button" class="btn btn-primary" id="searchButton">
                        <i class="bi bi-search"></i> 查询
                    </button>
                </div>
            </form>
        </div>
    </div>
    <div class="col-12 text-end mb-3">
        <button type="button" class="btn btn-sm btn-outline-secondary" id="fallbackButton"
                onclick="showBuildModal('/rule/build', 'fallback')">
            <i class="bi bi-arrow-left"></i> 回退
        </button>
        <button type="button" class="btn btn-sm btn-outline-primary me-5" id="deployButton"
                onclick="showBuildModal('/rule/build', 'deploy')">
            <i class="bi bi-rocket"></i> 部署
        </button>
        <button type="button" class="btn btn-sm btn-outline-info" id="addButton"
                onclick="showEditModalWithExtendedProperties('/rule/create', true)">
            <i class="bi bi-plus-lg"></i> 新增
        </button>
        <button type="button" class="btn btn-sm btn-outline-warning" id="editButton"
                onclick="showEditModalWithExtendedProperties('/rule/update', false)">
            <i class="bi bi-pencil-square"></i> 更新
        </button>
        <button type="button" class="btn btn-sm btn-danger" id="deleteButton"
                onclick="showDeleteModal('/rule/delete')">
            <i class="bi bi-trash"></i> 删除
        </button>
    </div>

    <table id="dataTable"
           data-toggle="table"
           data-method="get"
           data-url="/rule/page"
           data-sort-name="id"
           data-sort-order="desc"
           data-striped="true"
           data-pagination="true"
           data-detail-view="true"
           data-detail-formatter="detailFormatter"
           data-pagination-loop="false"
           data-side-pagination="server"
           data-click-to-select="true"
           data-maintain-selected="true">
        <thead>
        <tr>
            <th data-radio="true"></th>
            <th data-field="id">ID</th>
            <th data-field="type" data-formatter="typeFormatter">类型</th>
            <th data-field="name" data-sortable="true">名称</th>
            <th data-field="desc">描述</th>
            <th data-field="priority" data-sortable="true">优先级</th>
            <th data-field="score" data-sortable="true">评分</th>
            <th data-field="order" data-sortable="true">顺序</th>
            <th data-field="groupKey" data-formatter="groupKeyFormatter">规则组名称</th>
            <th data-field="enabled" data-formatter="enabledFormatter">是否可用</th>
        </tr>
        </thead>
    </table>
    <div class="card mt-1">
        <div class="card-header d-flex justify-content-between align-items-center">
            <h6 class="mb-0">规则单元</h6>
            <div>
                <button type="button" class="btn btn-sm btn-outline-info" id="addUnitButton"
                        onclick="showEditUnitModal('/rule/unit/create', true)">
                    <i class="bi bi-plus-lg"></i>
                </button>
                <button type="button" class="btn btn-sm btn-outline-warning" id="editUnitButton"
                        onclick="showEditUnitModal('/rule/unit/update', false)">
                    <i class="bi bi-pencil-square"></i>
                </button>
                <button type="button" class="btn btn-sm btn-danger" id="deleteUnitButton"
                        onclick="showDeleteUnitModal('/rule/unit/delete')">
                    <i class="bi bi-trash"></i>
                </button>
            </div>
        </div>
        <div class="card-body p-0">
            <ol class="list-group list-group-flush" id="ruleUnitList">
            </ol>
        </div>
    </div>
</div>

<div class="modal fade" id="editModal" tabindex="-1" aria-hidden="true">
    <div class="modal-dialog modal-lg">
        <div class="modal-content">
            <div class="modal-header">
                <h5 class="modal-title">编辑规则</h5>
                <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
            </div>
            <div class="modal-body">
                <form id="editForm">
                    <input type="hidden" id="editId" name="id">
                    <div class="row">
                        <div class="col-md-4 mb-3">
                            <label for="editType" class="form-label">类型</label>
                            <select class="form-select alk-select-type" id="editType" name="type" required>
                            </select>
                        </div>
                        <div class="col-md-8 mb-3">
                            <label for="editName" class="form-label">名称</label>
                            <input type="text" class="form-control" id="editName" name="name" required>
                        </div>
                    </div>
                    <div class="row">
                        <div class="col-md-12 mb-3">
                            <label for="editDesc" class="form-label">描述</label>
                            <textarea class="form-control" rows="3" id="editDesc" name="desc"
                                      required></textarea>
                        </div>
                    </div>
                    <div class="row">
                        <div class="col-md-4 mb-3">
                            <label for="editPriority" class="form-label">优先级</label>
                            <input type="number" class="form-control" id="editPriority" name="priority" value="0"
                                   required>
                        </div>
                        <div class="col-md-4 mb-3">
                            <label for="editScore" class="form-label">评分</label>
                            <input type="number" class="form-control" id="editScore" name="score" value="0" required>
                        </div>
                        <div class="col-md-4 mb-3">
                            <label for="editOrder" class="form-label">顺序</label>
                            <input type="number" class="form-control" id="editOrder" name="order" value="0" required>
                        </div>
                    </div>
                    <div class="row">
                        <div class="col-md-6 mb-3">
                            <label for="editGroupKey" class="form-label">规则组名称</label>
                            <select class="form-select alk-select-groupKey" id="editGroupKey" name="groupKey" required>
                            </select>
                        </div>
                        <div class="col-md-6 mb-3">
                            <label for="editEnabled" class="form-label">是否可用</label>
                            <select class="form-select" id="editEnabled" name="enabled" required>
                                <option value="true" selected>正常</option>
                                <option value="false">禁用</option>
                            </select>
                        </div>
                    </div>
                    <div class="mb-3">
                        <label class="form-label d-flex justify-content-between align-items-center">
                            扩展属性
                            <button type="button" class="btn btn-sm btn-success" id="addExtendedBtn">
                                <i class="bi bi-plus"></i> 添加
                            </button>
                        </label>
                        <div id="extendedPropertiesContainer">
                        </div>
                    </div>
                </form>
            </div>
            <div class="modal-footer">
                <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">取消</button>
                <button type="button" class="btn btn-primary" id="saveEditBtn">确认</button>
            </div>
        </div>
    </div>
</div>
<div class="modal fade" id="buildModal" tabindex="-1" aria-hidden="true">
    <div class="modal-dialog">
        <div class="modal-content">
            <div class="modal-header">
                <h5 class="modal-title">部署规则组</h5>
                <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
            </div>
            <div class="modal-body">
                <form id="buildForm">
                    <div class="row">
                        <div class="col-md-12 mb-3">
                            <label for="buildGroupKey" class="form-label">规则组</label><br>
                            <select class="form-select alk-select-groupKey" multiple id="buildGroupKey" name="groupKey"
                                    aria-describedby="buildGroupKeyDesc">
                                <option value="default_">默认组</option>
                            </select>
                            <div id="buildGroupKeyDesc" class="form-text">
                                可部署多个规则组，不选择则全部部署
                            </div>
                        </div>
                    </div>
                    <div class="row">
                        <div class="col-md-12 mb-3">
                            <label for="buildPath" class="form-label">路径</label>
                            <input type="text" class="form-control" id="buildPath" name="path"
                                   aria-describedby="pathDesc" required>
                            <div id="pathDesc" class="form-text">
                                例如：/deploy 或 /fallback 或 /rule/build
                            </div>
                        </div>
                    </div>
                    <div class="row">
                        <div class="col-md-12 mb-3">
                            <label for="buildUris" class="form-label">uris</label>
                            <textarea class="form-control" rows="3" id="buildUris" name="uris"
                                      aria-describedby="buildUrisDesc" required></textarea>
                            <div id="buildUrisDesc" class="form-text">
                                多个用逗号分割，例如：192.x.xx.xx:8000,192.xxx.xxx.xxx:8001
                            </div>
                        </div>
                    </div>
                </form>
            </div>
            <div class="modal-footer">
                <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">取消</button>
                <button type="button" class="btn btn-primary" id="saveBuildBtn">确认</button>
            </div>
        </div>
    </div>
</div>
<div class="modal fade" id="editUnitModal" tabindex="-1" aria-hidden="true">
    <div class="modal-dialog modal-xl">
        <div class="modal-content">
            <div class="modal-header">
                <h5 class="modal-title">编辑规则单元</h5>
                <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
            </div>
            <div class="modal-body">
                <form id="editUnitForm">
                    <input type="hidden" id="editUnitId" name="id">
                    <input type="hidden" id="editUnitRuleId" name="ruleId">
                    <input type="hidden" id="editUnitGroupKey" name="groupKey">
                    <div class="row">
                        <div class="col-md-6 mb-3">
                            <label for="editUnitDatasourceKey" class="form-label">外部数据源</label>
                            <select class="form-select" id="editUnitDatasourceKey" name="datasourceKey">
                            </select>
                        </div>
                        <div class="col-md-3 mb-3">
                            <label for="editUnitOrder" class="form-label">顺序</label>
                            <input type="number" class="form-control" id="editUnitOrder" name="order" value="0"
                                   required>
                        </div>
                        <div class="col-md-3 mb-3">
                            <label for="editUnitEnabled" class="form-label">是否可用</label>
                            <select class="form-select" id="editUnitEnabled" name="enabled" required>
                                <option value="true" selected>正常</option>
                                <option value="false">禁用</option>
                            </select>
                        </div>
                    </div>
                    <div class="col-md-12 mb-3">
                        <div class="d-flex justify-content-between align-items-center mb-2">
                            <label for="editUnitExpression" class="form-label mb-0">表达式</label>
                            <div class="d-flex gap-3">
                                <div class="btn-group" role="group" aria-label="Basic example">
                                    <button type="button" class="btn btn-sm btn-outline-primary"
                                            onclick="initRuleVariable('DATASOURCE')">
                                        <i class="bi bi-database"></i> 外部数据源
                                    </button>
                                    <button type="button" class="btn btn-sm btn-outline-primary"
                                            onclick="initRuleVariable('PARAM')">
                                        <i class="bi bi-textarea-resize"></i> 预处理入参
                                    </button>
                                    <button type="button" class="btn btn-sm btn-outline-primary"
                                            onclick="initRuleVariable('VAR')">
                                        <i class="bi bi-input-cursor-text"></i> 变量
                                    </button>
                                    <button type="button" class="btn btn-sm btn-outline-primary"
                                            onclick="initRuleVariable('FUNC')">
                                        <i class="bi bi-code-slash"></i> 函数
                                    </button>
                                    <button type="button" class="btn btn-sm btn-outline-primary"
                                            onclick="initRuleVariable('OPE')">
                                        <i class="bi bi-cpu"></i> 运算符
                                    </button>
                                </div>
                                <button type="button" class="btn btn-sm btn-outline-info"
                                        onclick="validateExpression()">
                                    <i class="bi bi-check-circle"></i> 语法检查
                                </button>
                            </div>
                        </div>
                        <textarea class="form-control" rows="5" id="editUnitExpression" name="expression"
                                  required></textarea>
                    </div>
                    <div id="ruleVariableList" class="d-flex flex-wrap gap-2 overflow-auto" style="max-height: 30vh;">
                    </div>
                </form>
            </div>
            <div class="modal-footer">
                <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">取消</button>
                <button type="button" class="btn btn-primary" id="saveEditUnitBtn">确认</button>
            </div>
        </div>
    </div>
</div>
<div class="modal fade" id="deleteModal" tabindex="-1" aria-hidden="true">
    <div class="modal-dialog">
        <div class="modal-content">
            <div class="modal-header">
                <h5 class="modal-title">删除规则</h5>
                <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
            </div>
            <div class="modal-body">
                <p>确定要删除选中的记录？</p>
            </div>
            <div class="modal-footer">
                <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">取消</button>
                <button type="button" class="btn btn-danger" id="saveDeleteBtn">确认</button>
            </div>
        </div>
    </div>
</div>

<script th:src="@{/webjars/jquery/jquery.min.js}"></script>
<script th:src="@{/webjars/bootstrap/js/bootstrap.bundle.min.js}"></script>
<script th:src="@{/webjars/bootstrap-table/dist/bootstrap-table.min.js}"></script>
<script th:src="@{/webjars/bootstrap-table/dist/locale/bootstrap-table-zh-CN.min.js}"></script>
<script th:src="@{/webjars/tom-select/dist/js/tom-select.complete.min.js}"></script>
<script th:src="@{/js/table.js}"></script>
<script>
    initRuleGroupSelect(function () {
        const $buildGroupKey = $('#buildGroupKey');
        const tomSelect = new TomSelect($buildGroupKey, {
            plugins: ['remove_button'],
            placeholder: '请选择...'
        });
        $buildGroupKey.data('tomSelect-instance', tomSelect);
    });
    initTypeSelect();
    initTable();
    initTableRowEvent();
    initExtendedProperties();
    initDatasourceMapping();

    function initTypeSelect() {
        httpClient('/rule/type', 'GET', null, function (data) {
            const map = new Map(Object.entries(data));
            map.forEach((value, key) => {
                $('.alk-select-type').append($('<option>', {value: key, text: value}))
            });
        });
    }

    function initDatasourceSelect(groupKey) {
        const $editUnitDatasourceKey = $('#editUnitDatasourceKey');
        $editUnitDatasourceKey.empty();
        $editUnitDatasourceKey.append($('<option>', {value: '', text: '无'}))
        const mapping = getDatasourceMapping(groupKey);
        mapping.forEach((value, key) => {
            $editUnitDatasourceKey.append($('<option>', {value: key, text: key + ' : ' + value}))
        });
    }

    function initDatasourceMapping() {
        httpClient('/rule/datasource/map', 'GET', null, function (data) {
            $('#ruleUnitList').data('datasource-mapping', JSON.stringify(data));
        });
    }

    function getDatasourceMapping(groupKey) {
        const datasourceMapping = $('#ruleUnitList').data('datasource-mapping');
        const mapping = new Map(Object.entries(JSON.parse(datasourceMapping))).get(groupKey);
        return new Map(Object.entries(mapping));
    }

    function initTableRowEvent() {
        $('#dataTable').on('click-row.bs.table', function (event, row, $element) {
            buildUnits(row.groupKey, row.id);
        });

        $(document).on('click', '.list-group-item', function () {
            $('.list-group-item').removeClass('light-active');
            $(this).addClass('light-active');
        });
    }

    function typeFormatter(arg) {
        const keyValuePairs = {};
        $('select#type option').each(function () {
            keyValuePairs[$(this).val()] = $(this).text();
        });
        return keyValuePairs[arg];
    }

    function showEditUnitModal(url, created) {
        const selections = $('#dataTable').bootstrapTable('getSelections');
        if (selections.length !== 1) {
            showWarningToast("请选择一条记录");
            return;
        }
        const row = selections[0];

        initDatasourceSelect(row.groupKey);

        if (created) {
            $('#editUnitForm')[0]?.reset();
            $('#editUnitId').val('');
            $('#editUnitRuleId').val(row.id);
            $('#editUnitGroupKey').val(row.groupKey);
        } else {
            const selection = $(".list-group-item.light-active");
            if (selection.length !== 1) {
                showWarningToast("请选择一条记录");
                return;
            }
            $('#editUnitId').val(selection.data('id'));
            $('#editUnitRuleId').val(selection.data('rule-id'));
            $('#editUnitGroupKey').val(selection.data('group-key'));
            $('#editUnitExpression').val(selection.data('expression'));
            $('#editUnitOrder').val(selection.data('order'));
            $('#editUnitEnabled').val(selection.data('enabled') ? "true" : "false");
            $('#editUnitDatasourceKey').val(selection.data('datasource-key'));
        }

        $('#ruleVariableList').empty();
        $('#editUnitModal').modal('show');
        $('#saveEditUnitBtn').off('click').on('click', function (event) {
            const formData = {};
            const $editForm = $('#editUnitForm');
            if (!$editForm[0].checkValidity()) {
                event.preventDefault();
                event.stopPropagation();
                $editForm.addClass('was-validated');
            } else {
                $editForm.serializeArray().forEach(item => {
                    formData[item.name] = item.value;
                });
                httpClient(url, created ? 'POST' : 'PUT', formData, function () {
                    $('#editUnitModal').modal('hide');
                    buildUnits(row.groupKey, row.id);
                });
            }
        });
    }

    function showDeleteUnitModal(url) {
        const selection = $(".list-group-item.light-active");
        if (selection.length !== 1) {
            showWarningToast("请选择一条记录");
            return;
        }

        $('#deleteModal').modal('show');
        $('#saveDeleteBtn').off('click').on('click', function () {
            httpClient(url + '?id=' + selection.data('id'), 'DELETE', null, function () {
                $('#deleteModal').modal('hide');
                const row = $('#dataTable').bootstrapTable('getSelections')[0];
                buildUnits(row.groupKey, row.id);
            });
        });
    }

    function showBuildModal(url, type) {
        const $buildGroupKey = $('#buildGroupKey');
        const tomSelect = $buildGroupKey.data('tomSelect-instance');
        tomSelect.clear();
        $('#buildPath').empty();
        $('#buildUris').empty();

        const $buildModal = $('#buildModal');
        if (type === 'fallback') {
            $buildModal.find('.modal-title').text('回退规则组');
            $buildGroupKey.parent().hide();
        } else {
            $buildModal.find('.modal-title').text('部署规则组');
            $buildGroupKey.parent().show();
        }

        $buildModal.modal('show');
        $('#saveBuildBtn').off('click').on('click', function (event) {
            const formData = {};
            const $buildForm = $('#buildForm');
            if (!$buildForm[0].checkValidity()) {
                event.preventDefault();
                event.stopPropagation();
                $buildForm.addClass('was-validated');
            } else {
                formData['path'] = $('#buildPath').val();
                formData['uris'] = $('#buildUris').val().split(",").map(item => item.trim());
                formData['ruleGroups'] = type === 'fallback' ? null : tomSelect.getValue();
                httpClient(url, 'POST', formData, function (data) {
                    showWarningToast(JSON.stringify(data, null, 2));
                    $buildModal.modal('hide');
                });
            }
        });
    }

    function buildUnits(groupKey, ruleId) {
        const mapping = getDatasourceMapping(groupKey);

        $('#ruleUnitList').empty();
        httpClient('/rule/unit/list?ruleId=' + ruleId, 'GET', null, function (data) {
            if (!data || data.length === 0) {
                showErrorToast('未查询到规则单元');
            } else {
                data.forEach(field => {
                    const status = enabledFormatter(field.enabled);
                    const datasource = field.datasourceKey ? field.datasourceKey + ' : ' + mapping.get(field.datasourceKey) : '无';
                    const property = `
                      <li class="list-group-item"
                      data-id="${field.id}"
                      data-expression="${field.expression}"
                      data-datasource-key="${field.datasourceKey}"
                      data-rule-id="${field.ruleId}"
                      data-group-key="${field.groupKey}"
                      data-enabled="${field.enabled}"
                      data-order="${field.order}">
                          <div class="d-flex justify-content-between mb-2">
                              <span class="badge ${field.datasourceKey ? 'text-bg-primary' : 'text-bg-warning'}">${datasource}</span>
                              <span class="badge ${field.enabled ? 'text-bg-success' : 'text-bg-danger'}">${status}</span>
                          </div>
                          <div class="ms-2 me-auto">${field.expression}</div>
                      </li>
                    `;
                    $('#ruleUnitList').append(property);
                });
            }
        });
    }

    function validateExpression() {
        const value = $('#editUnitExpression').val();
        if (!value) {
            showWarningToast("表达式不能为空");
        } else {
            httpClient('/rule/validate', 'PUT', value,
                function (data) {
                    showSuccessToast("表达式校验通过");
                }, function (msg) {
                    showErrorToast("表达式校验失败: " + msg);
                });
        }
    }

    function initRuleVariable(type) {
        $('#ruleVariableList').empty();
        const groupKey = $('#editUnitGroupKey').val();
        const url = "/rule/variable/list?groupKey=" + groupKey + "&type=" + type;

        httpClient(url, 'GET', null, function (data) {
            if (!data || data.length === 0) {
                showWarningToast('未配置规则变量');
            } else {
                data.forEach(field => {
                    const property = `
                       <span class="badge bg-secondary clickable-badge"
                         onclick="insertAtCursor('${field.key}')"
                         title="${field.desc}">${field.key}（${field.name}）</span>
                   `;
                    $('#ruleVariableList').append(property);
                });
            }
        });
    }

    function insertAtCursor(text) {
        const $textarea = $('#editUnitExpression');
        const textarea = $textarea[0];
        const start = textarea.selectionStart;
        const end = textarea.selectionEnd;
        const currentValue = textarea.value;

        textarea.value = currentValue.substring(0, start) + text + currentValue.substring(end) + " ";
        textarea.selectionStart = textarea.selectionEnd = start + text.length + 1;
        textarea.focus();
    }
</script>
</body>
</html>